package com.bitejiuyeke.biteportalservice.homepage.service.impl;

import com.bitejiuyeke.biteadminapi.config.domain.dto.DictionaryDataDTO;
import com.bitejiuyeke.biteadminapi.config.feign.DictionaryFeignClient;
import com.bitejiuyeke.bitecommoncore.utils.BeanCopyUtil;
import com.bitejiuyeke.bitecommoncore.utils.JsonUtil;
import com.bitejiuyeke.bitecommonredis.service.RedisService;
import com.bitejiuyeke.biteportalservice.homepage.domain.dto.DicDataDTO;
import com.bitejiuyeke.biteportalservice.homepage.service.IDictionaryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class DictionaryServiceImpl implements IDictionaryService {

    private static final String DICT_TYPE_PREFIX = "applet:dict:type:";
    private static final Long DICT_TYPE_TIMEOUT = 5L;
    private static final String DICT_DATA_PREFIX = "applet:dict:data:";
    private static final Long DICT_DATA_TIMEOUT = 5L;

    @Autowired
    private DictionaryFeignClient dictionaryFeignClient;

    @Autowired
    private RedisService redisService;
    @Override
    public Map<String, List<DicDataDTO>> batchFindDictionaryDataByTypes(List<String> types) {
        Map<String, List<DicDataDTO>> resultMap = new HashMap<>();
        //先从缓存中获取
        List<String> notCacheTypes = new ArrayList<>();
        for(String type: types){
            List<DicDataDTO> dataDTOList = getCacheList(type);
            if(CollectionUtils.isEmpty(dataDTOList)){
                notCacheTypes.add(type);//走feign获取
            }else{
                resultMap.put(type, dataDTOList);//直接返回缓存结果
            }
        }
        //如果全部命中，返回
        if(CollectionUtils.isEmpty(notCacheTypes)){
            return resultMap;
        }
        //从feign获取未命中的数据
        Map<String, List<DictionaryDataDTO>> map = dictionaryFeignClient.selectDictDataByTypes(notCacheTypes);
        if(CollectionUtils.isEmpty(map)){
            log.error("字典类型不存在！ notCacheTypes:{}", JsonUtil.obj2String(notCacheTypes));
            return resultMap;//即使失败，也要返回已有的缓存部分
        }

        for (Map.Entry<String, List<DictionaryDataDTO>> entry: map.entrySet()){
            List<DicDataDTO> dataDTOList = BeanCopyUtil.copyListProperties(entry.getValue(), DicDataDTO::new);
            cacheList(entry.getKey(), dataDTOList);
            resultMap.put(entry.getKey(), dataDTOList);
        }
        return resultMap;
    }

    @Override
    public Map<String, DicDataDTO> batchFindDictionaryData(List<String> dataKeys) {
        Map<String, DicDataDTO> resultMap = new HashMap<>();
        //先从缓存中获取
        List<String> notCacheDataKeys = new ArrayList<>();
        for(String dataKey: dataKeys){
            DicDataDTO dicDataDTO = getDataCache(dataKey);
            if(null == dicDataDTO){
                notCacheDataKeys.add(dataKey);
            }else{
                resultMap.put(dataKey, dicDataDTO);
            }
        }
        //全部存在：返回
        if(CollectionUtils.isEmpty(notCacheDataKeys)){
            return resultMap;
        }
        //从feign获取未命中的数据
        List<DictionaryDataDTO> dataDTOList = dictionaryFeignClient.getDicDataByKeys(notCacheDataKeys);
        if(CollectionUtils.isEmpty(dataDTOList)){
            log.error("字典数据不存在！ notCacheDataKeys:{}", JsonUtil.obj2String(notCacheDataKeys));
            return resultMap;
        }

        //缓存结果
        for(DictionaryDataDTO dictionaryDataDTO : dataDTOList){
            DicDataDTO dicDataDTO = new DicDataDTO();
            BeanCopyUtil.copyProperties(dictionaryDataDTO, dicDataDTO);
            cacheData(dictionaryDataDTO.getDataKey(), dicDataDTO);
            resultMap.put(dictionaryDataDTO.getDataKey(), dicDataDTO);
        }
        return resultMap;
    }

    private DicDataDTO getDataCache(String dataKey) {
        if(StringUtils.isEmpty(dataKey)){
            return null;
        }
        String str = redisService.getCacheObject(DICT_DATA_PREFIX + dataKey, String.class);
        if (StringUtils.isEmpty(str)){
            return null;
        }
        return JsonUtil.string2Obj(str, DicDataDTO.class);
    }

    private void cacheData(String dataKey, DicDataDTO dicDataDTO) {
        if(StringUtils.isEmpty(dataKey)){
            return;
        }
        redisService.setCacheObject(
                DICT_DATA_PREFIX + dataKey,
                JsonUtil.obj2String(dicDataDTO),
                DICT_DATA_TIMEOUT,
                TimeUnit.MINUTES
        );
    }

    private List<DicDataDTO> getCacheList(String type) {
        if(StringUtils.isBlank(type)){
            return Arrays.asList();
        }
        String str = redisService.getCacheObject(DICT_TYPE_PREFIX + type, String.class);
        if(StringUtils.isBlank(str)){
            return Arrays.asList();
        }
        return JsonUtil.string2List(str, DicDataDTO.class);
    }

    private void cacheList(String key, List<DicDataDTO> dataDTOList) {
        if(StringUtils.isBlank(key)){
            return;
        }
        redisService.setCacheObject(
                DICT_TYPE_PREFIX + key,
                JsonUtil.obj2String(dataDTOList),
                DICT_TYPE_TIMEOUT,
                TimeUnit.MINUTES
        );
    }

}
